--- /dev/null
+#!/usr/bin/env gjs
+//
+// Copyright (C) 2014 Colin Walters <walters@verbum.org>
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the
+// Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+// Boston, MA 02111-1307, USA.
+
+const GLib = imports.gi.GLib;
+const Gio = imports.gi.Gio;
+const OSTree = imports.gi.OSTree;
+
+let repoPathArg = ARGV[0];
+let refToCorrupt = ARGV[1];
+
+let repo = OSTree.Repo.new(Gio.File.new_for_path(repoPathArg));
+
+repo.open(null);
+
+function listObjectChecksumsRecurse(dir, allObjects) {
+ dir.ensure_resolved();
+ allObjects[dir.tree_get_contents_checksum() + '.dirtree'] = true;
+ allObjects[dir.get_checksum() + '.dirmeta'] = true;
+ let e = dir.enumerate_children('standard::name,standard::type', 0, null);
+ let info;
+ while ((info = e.next_file(null)) != null) {
+ let child = e.get_child(info);
+ child.ensure_resolved();
+ print(info.get_name() + " is " + info.get_file_type());
+ if (info.get_file_type() == Gio.FileType.DIRECTORY) {
+ listObjectChecksumsRecurse(child, allObjects);
+ } else {
+ allObjects[child.get_checksum() + '.filez'] = true;
+ }
+ }
+ e.close(null);
+}
+
+let [,commit] = repo.resolve_rev(refToCorrupt, false);
+let [,root,commit] = repo.read_commit(refToCorrupt, null);
+let allObjects = {};
+allObjects[commit + '.commit'] = true;
+listObjectChecksumsRecurse(root, allObjects);
+let i = 0;
+for (let v in allObjects)
+ i++;
+print("commit " + commit + " refers to " + i + " objects");
+let offset = GLib.random_int_range(0, i);
+let objectToCorrupt = null;
+for (let v in allObjects) {
+ if (offset <= 0) {
+ objectToCorrupt = v;
+ break;
+ }
+ offset--;
+}
+print("Choosing " + objectToCorrupt + " to corrupt");
+
+let loosePath = repo.get_path().resolve_relative_path('objects/' + objectToCorrupt.substring(0, 2) + "/" + objectToCorrupt.substring(2));
+
+let iostream = loosePath.open_readwrite(null);
+let info = iostream.query_info('standard::size', null);
+let size = info.get_size();
+let byteOffsetToCorrupt = GLib.random_int_range(0, size);
+iostream.seek(byteOffsetToCorrupt, GLib.SeekType.SET, null);
+let datain = Gio.DataInputStream.new(iostream.get_input_stream());
+let dataout = Gio.DataOutputStream.new(iostream.get_output_stream());
+let inbyte = datain.read_byte(null);
+let outbyte = (inbyte + 1) % 255;
+dataout.put_byte(outbyte, null);
+dataout.flush(null);
+iostream.close(null);
+let status = "Changed byte offset " + byteOffsetToCorrupt + " from " + inbyte + " to " + outbyte;
+print(status);
+
+let successFile = Gio.File.new_for_path('corrupted-status.txt');
+successFile.replace_contents(status, null, false, 0, null);
fi
}
-# Corrupt .dirmeta
-someobject=$(find ${repopath} -name '*.dirmeta' | head -1)
-echo "garbage garbage garbage" > ${someobject}
+# FIXME - ignore errors here since gjs in RHEL7 has the final
+# unrooting bug
+gjs $(dirname $0)/corrupt-repo-ref.js ${repopath} main || true
+assert_file_has_content corrupted-status.txt 'Changed byte'
do_corrupt_pull_test
-echo "ok corrupt dirmeta"
-
-# Corrupt .dirtree
-someobject=$(find ${repopath} -name '*.dirtree' | head -1)
-echo "garbage garbage garbage" > ${someobject}
-do_corrupt_pull_test
-echo "ok corrupt dirtree"
-
-# Corrupt .filez
-someobject=$(find ${repopath} -name '*.filez' | head -1)
-otherobject=$(find ${repopath} -name '*.filez' | head -2 | tail -1)
-cp ${someobject} ${otherobject}
-do_corrupt_pull_test
-echo "ok corrupt filez"
+echo "ok corruption $iteration"